#include <iostream>
#include <vector>
# include <windows.h>
#include "./include/rapidjson/document.h"
#include "./include/rapidjson/writer.h"

using namespace std;
using namespace rapidjson;

const string userNamePre = "测试名称 c++/go/cangjie 编程语言 json序列化、反序列化性能大比拼 - ";
float scoreBase = 65.5;
int ageBase = 18;

class Stu {
public :
    string name;
    int sex;
    int age;
    float score;

    Stu(string name, int sex, int age, float score) : name(name), sex(sex), age(age), score(score) {};
};

// 将结构体转为 json 文档值
void StuToJson(unique_ptr<Stu> &stu, Value &value, Document::AllocatorType &allocator) {
    value.SetObject();
    Value val;

    value.AddMember("name", Value(StringRef(stu->name.c_str()), allocator), allocator);
    value.AddMember("sex", val.SetInt(stu->sex), allocator);
    value.AddMember("age", val.SetInt(stu->age), allocator);
    value.AddMember("score", val.SetFloat(stu->score), allocator);
}

Stu JsonToStu(const Value &jValue) {
    // 确保传入的是一个对象类型的 Value
    if (!jValue.IsObject()) {
        throw std::runtime_error("Invalid JSON format for Stu");
    }

    // 从 JSON 中提取 Stu 的属性
    const char *name = jValue["name"].GetString();
    int sex = jValue["sex"].GetInt();
    int age = jValue["age"].GetInt();
    float score = jValue["score"].GetFloat();

    // 创建并返回 Stu 对象
    return Stu(name, sex, age, score);
}

// 解析 JSON 中的 list 数组到 vector<Stu>
vector<Stu> ParseListToStuVector(const Value &list) {
    vector<Stu> stuVector;

    // 确保文档已经成功解析，并且 list 存在且为数组类型
    if (!list.IsArray()) {
        throw std::runtime_error("list 成员必须是 array 类型");
    }

//    const rapidjson::Value &list = document["list"];
    stuVector.reserve(list.Size());
    for (const auto &stuJson: list.GetArray()) {
        // 解析每个 JSON 对象到 Stu 类
        Stu stu = JsonToStu(stuJson);
        // 将 Stu 对象添加到 vector 中
        stuVector.push_back(stu);
    }

    return stuVector;
}

// 构建 json 文档结构
Document BuildJsonDocument(Value &listData, Document::AllocatorType &allocator) {
    Document document;
    document.SetObject();
    Value value;
    document.AddMember("code", value.SetInt(200), allocator);
    document.AddMember("msg", value.SetString("成功"), allocator);
    document.AddMember("list", listData, allocator);

    return document;
}

// 将 json文档序列化为文本(string)
string JsonEncode(const Document &jsonDoc) {
    StringBuffer buffer;
    // 创建Writer对象，将document写入到buffer中
    Writer<StringBuffer> writer(buffer);
    jsonDoc.Accept(writer);
    return buffer.GetString();
}

struct Response {
    int code{};
    string msg{};
    vector<Stu> list{};
};

// jsonDecode
Response JsonDecode(const string &jsString) {
    rapidjson::Document doc;
    if (doc.Parse(jsString.c_str()).HasParseError()) {
        std::cout << "json 解析错误:" << doc.GetParseError() << endl;
        return Response(0, "", vector<Stu>());
    }

    return Response{
            .code=doc["code"].GetInt(),
            .msg=doc["msg"].GetString(),
            .list=    ParseListToStuVector(doc["list"]),
    };

}


// 初始化 N 个对象数组
void InitStu(int num, Value &valueArr, Document::AllocatorType &allocator) {
    for (int i = 0; i < num; i++) {
        unique_ptr<Stu> tmpStu(new Stu(userNamePre + to_string(i), i % 2, ageBase + i, scoreBase + float(i)));
        // 将普通对象转为 value 对象
        Value tmpValueObj(kObjectType);
        StuToJson(tmpStu, tmpValueObj, allocator);
        valueArr.PushBack(tmpValueObj, allocator);
    }
}

int main() {
    // 创建一个Document对象，它是一个空的JSON对象
    Document document;
    Document::AllocatorType &allocator = document.GetAllocator();
    Value valueArr(kArrayType);
    int rows = 1000000;     // 初始化 100 万个对象
    valueArr.Reserve(rows, document.GetAllocator());
    InitStu(rows, valueArr, allocator);
    //构建 json 文档结构
    Document jsonDoc = BuildJsonDocument(valueArr, allocator);
    string jsonStr = JsonEncode(jsonDoc);
    // ↑↑↑  以上构建json字符串的过程我们跳过计时，因为json序列化已经在前一个场景测试结束了 ↑↑↑

    DWORD startSec = GetTickCount();
    Response resp;
    // 将json文本反序列为原始对象
    for (int i = 0; i < 10; i++) {
        // json 文档序列化为 json 文本
        resp = JsonDecode(jsonStr);
    }

    DWORD useMillionSecond = (GetTickCount() - startSec) / 10;

    cout << "json字符串反序列化后信息——code：" << resp.code << ", msg: " << resp.msg << ", listLen: " << resp.list.size() << endl;
    cout << "100万个对象(Stu) json 文本反序列化，单次平均耗时(ms)：" << useMillionSecond << endl;

    return 0;
}
